Imports System.IO.IsolatedStorage
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics
Imports Runa
Imports Runa.Common.Helper
Imports Runa.UI.Input
Imports Runa.Resources.ResourceManager
Imports Runa.Resources.ContentManagers
Imports Runa.Core.Services
Imports Runa.Foundation
Imports Runa.Foundation.Diagnostics
Imports Runa.Foundation.Messaging
Imports Runa.Foundation.Runtime
Imports Runa.Foundation.Threading
Imports Runa.Scripting.ScriptingHost
Imports Runa.Core.GamePackage
Imports Runa.Foundation.Runtime.Serialization

#If Not NETFX_CORE Then
Imports System.Windows.Forms
#Else
#End If

''' <summary>
''' This is the main type for your game
''' </summary>
Partial Public Class GameRender
    Inherits Microsoft.Xna.Framework.Game

    Public WithEvents SystemSpriteBatch As SpriteBatch

    Public Sub New()
        Me.m_graphics = New GraphicsDeviceManager(Me)
        If GameRender.GamePackage Is Nothing Then Throw New ArgumentException("Null game package.")
        With GameRender.GamePackage
            Me.m_physicalStorage = .PhysicalStorage
            Me.Name = .Name
            Me.Author = .Author
            Me.Fps = .Fps
            Me.GPUAccelerationEnabled = .GPUAccelerationEnabled
#If (Not NETFX_CORE) And (Not WINDOWS_PHONE) Then
            Me.WindowHeight = .WindowHeight
            Me.WindowWidth = .WindowWidth
            Me.m_graphics.IsFullScreen = .IsFullScreen
#End If
            Me.GameContentRoot = .GameContentRoot
        End With
    End Sub

    ''' <summary>
    ''' Import information from the package extractor.
    ''' </summary>
    ''' <param name="pkgExtractor"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal pkgExtractor As GamePackageBase)
        Me.m_graphics = New GraphicsDeviceManager(Me)
        GameRender.GamePackage = pkgExtractor
        With pkgExtractor
            Me.m_physicalStorage = .PhysicalStorage
            Me.Name = .Name
            Me.Author = .Author
            Me.Fps = .Fps
#If (Not NETFX_CORE) And (Not WINDOWS_PHONE) Then
            Me.WindowHeight = .WindowHeight
            Me.WindowWidth = .WindowWidth
            Me.m_graphics.IsFullScreen = .IsFullScreen
#End If
            Me.GameContentRoot = .GameContentRoot
        End With
    End Sub

    Protected Overrides Sub Initialize()
        Dim oldResolution As New Vector2
        With Me
            Me.m_graphics.TryChangeResolution(New Vector2(.WindowWidth, .WindowHeight), oldResolution)
        End With

        Me.Services.AddService(GetType(IGameParameterService), Me)
        Me.Services.AddService(GetType(ISafeNativeMethods), Me)

        Me.m_contentManager = New GameDirectoryContentManager(Me.Game.Content.ServiceProvider, Me.GameContentRoot, Me.m_physicalStorage)
        Me.GameTracer = Tracer.Add(Me.Name, Path.Combine(Me.m_contentManager.RootDirectory, Me.Name))

        Me.Content = Me.m_contentManager

        Me.RegisterWindowClass(Me)

        Call BindingInputDeviceEvent()

        ' Initialize the ScriptTask object for GameLoop class.
        Dim gameLoopScriptTask = New ScriptTask("GameLoop.rb")
        Me.ScriptObjects.Add("GameLoop", gameLoopScriptTask)
        Me.BindingScriptTaskOnErrorEvent()
        Me.BindingScriptTaskOnOnCompilationFailedEvent()
        gameLoopScriptTask.LoadScriptFromGameDirectory(Path.Combine(Me.m_contentManager.RootDirectory, "GameLoop.rb"), Me.m_physicalStorage)

        Call AddBasicReference(gameLoopScriptTask)
        gameLoopScriptTask.Execute(
            "gl = GameLoop.new(MyGame)" & vbCrLf & _
            "gl", _
            New System.MutableTuple(Of String, Object)("MyGame", Me))
        Me.BasicGameLoop = CType(gameLoopScriptTask.Result, BasicGameLoopGameComponent)

        Try
            Me.BasicGameLoop.Initialize()
            MyBase.Initialize()
        Catch ex As Exception
            Runa.Foundation.Diagnostics.Tracer.Default.TraceMessage(ex.Message & ex.StackTrace.ToString())
        End Try
    End Sub

    Protected Overrides Sub LoadContent()
        Me.SystemSpriteBatch = New SpriteBatch(GraphicsDevice)

        Try
            Me.LastScreenShot = New RenderTarget2D(GraphicsDevice, Me.WindowWidth, Me.WindowHeight, False, SurfaceFormat.Color, Nothing)
        Catch ex As Exception
            Me.LastScreenShot = New RenderTarget2D(GraphicsDevice, Me.WindowWidth, Me.WindowHeight)
        End Try

        If Me.m_contentManager.PhysicalStorage.FileExists(Me.SaveDataFileName) Then
            Using fs = Me.m_contentManager.PhysicalStorage.OpenFile(Me.SaveDataFileName, FileMode.Open)
                Try
                    Me.GlobalStatus = Me.m_Serializer.Deserialize(Of Dictionary(Of String, Object))(fs)
                Catch ex As Exception
                    Exit Try
                End Try
            End Using
        End If

        Try
#If DEBUG Then
            Me.m_gameLoaded = False
            Me.BasicGameLoop.LoadContent()
            MyBase.LoadContent()
            Me.m_gameLoaded = True
#Else
#If Not NETFX_CORE Then
        Dim thr As New System.Threading.Tasks.Task(
            Sub()
#End If
                Me.m_gameLoaded = False

                Me.BasicGameLoop.LoadContent()

                MyBase.LoadContent()

                Me.m_gameLoaded = True
#If Not NETFX_CORE Then
            End Sub)
        thr.Start()
#End If
#End If
        Catch ex As Exception
            Runa.Foundation.Diagnostics.Tracer.Default.TraceMessage(ex.Message & ex.StackTrace.ToString())
        End Try
    End Sub

    Protected Overrides Sub UnloadContent()
        GlobalSave()
        MyBase.UnloadContent()
    End Sub

    Protected Overrides Sub Update(gameTime As Microsoft.Xna.Framework.GameTime)
        ' TODO: Add your update logic here
        If Me.m_gameLoaded = True Then
            Dim gt As New GameTimeEventArgs(gameTime)

            Dim msg As Runa.Foundation.Messaging.Message = Nothing
            If Me.PeekMessage(msg, Thread.CurrentThread.ThreadID, True) Then
                Me.WndProc(msg)
            End If

            Me.UpdateTimers(gt)
            Me.BasicGameLoop.Update(gt)
            MyBase.Update(gameTime)
        End If
    End Sub

    Private Sub OnDraw(ByVal gameTime As GameTime)
        If Me.m_gameLoaded = True Then
            Dim gt As New GameTimeEventArgs(gameTime)
            Me.BasicGameLoop.Draw(gt)
            MyBase.Draw(gameTime)
        End If
    End Sub

    Protected Overrides Sub Draw(gameTime As Microsoft.Xna.Framework.GameTime)
        ' TODO: Add your drawing code here
        MyBase.GraphicsDevice.Clear(Color.Black)
        If Me.m_screenShotGotton = True Then
            SyncLock Me.LastScreenShot
                Me.GraphicsDevice.SetRenderTarget(Me.LastScreenShot)
                Call Me.OnDraw(gameTime)
                Me.EndTakeScreenShot()
            End SyncLock
        Else
            Call Me.OnDraw(gameTime)
        End If
    End Sub

    Private Sub OnInputDataArrived(sender As Object, e As InputEventArgs)
        Try
            If Me.m_gameLoaded = True Then
                Dim msg = Runa.Foundation.Messaging.Message.Create(Nothing, e.Message, e.ChangedProperty, CType(sender, InputHandler))
                ' Me.SendMessage(msg)
                msg.HWnd = New Object()
                Me.TranslateMessage(msg)
                Me.DispachMessage(msg)
            End If
        Catch ex As Exception
            Exit Sub
        End Try
    End Sub

End Class